import { api } from 'dicomweb-client'
import dcmjs from 'dcmjs'
import { calculateSUVScalingFactors } from '@cornerstonejs/calculate-suv'
import { getPTImageIdInstanceMetadata } from './getPTImageIdInstanceMetadata'
import { utilities } from '@cornerstonejs/core'
import cornerstoneDICOMImageLoader from '@cornerstonejs/dicom-image-loader'

import ptScalingMetaDataProvider from './ptScalingMetaDataProvider'
import getPixelSpacingInformation from './getPixelSpacingInformation'
import { convertMultiframeImageIds } from './convertMultiframeImageIds'
import removeInvalidTags from './removeInvalidTags'
import getImgInfoProvider from '@/config/getImgInfoProvider'
import generalImageModuleProvider from '@/config/generalImageModuleProvider'
import { DICOM_TAG_ATTR } from '@/types/types'
import { PACS_SETTING } from '@/config/config'

const { DicomMetaDictionary } = dcmjs.data
const { calibratedPixelSpacingMetadataProvider } = utilities

/**
 /**
 * Uses dicomweb-client to fetch metadata of a study, cache it in cornerstone,
 * and return a list of imageIds for the frames.
 *
 * Uses the app config to choose which study to fetch, and which
 * dicom-web server to fetch it from.
 *
 * @returns {string[]} An array of imageIds for instances in the study.
 */

export default async function createImageIdsAndCacheMetaData({
                                                               StudyInstanceUID,
                                                               SeriesInstanceUID,
                                                               SOPInstanceUID = null,
                                                               wadoRsRoot,
                                                               client = null
                                                             }) {
  const SOP_INSTANCE_UID = '00080018'
  const SERIES_INSTANCE_UID = '0020000E'
  const MODALITY = '00080060'

  const studySearchOptions = {
    studyInstanceUID: StudyInstanceUID,
    seriesInstanceUID: SeriesInstanceUID
  }
  // 添加auth
  client = client || new api.DICOMwebClient({
      url: wadoRsRoot,
      headers: PACS_SETTING.OpenAuth ? {
        'Authorization': 'Basic ' + btoa(PACS_SETTING.username + ':' + PACS_SETTING.password)
      } : {}
    }
  )
  let instances = await client.retrieveSeriesMetadata(studySearchOptions)
  const sopInstanceId = instances[0]['00080018'].Value[0]

  // if sop instance is provided we should filter the instances to only include the one we want
  if (SOPInstanceUID) {
    instances = instances.filter((instance) => {
      return instance[SOP_INSTANCE_UID].Value[0] === SOPInstanceUID
    })
  }

  const modality = instances[0][MODALITY].Value[0]
  let imageIds = instances.map((instanceMetaData) => {
    const SeriesInstanceUID = instanceMetaData[SERIES_INSTANCE_UID].Value[0]
    const SOPInstanceUIDToUse =
      SOPInstanceUID || instanceMetaData[SOP_INSTANCE_UID].Value[0]
    const prefix = 'wadors:'

    const imageId =
      prefix +
      wadoRsRoot +
      '/studies/' +
      StudyInstanceUID +
      '/series/' +
      SeriesInstanceUID +
      '/instances/' +
      SOPInstanceUIDToUse +
      '/frames/1'
    generalImageModuleProvider.add(imageId, {
      sopInstanceUid: SOPInstanceUIDToUse
    })
    cornerstoneDICOMImageLoader.wadors.metaDataManager.add(
      imageId,
      instanceMetaData
    )
    return imageId
  })

  // if the image ids represent multiframe information, creates a new list with one image id per frame
  // if not multiframe data available, just returns the same list given
  imageIds = convertMultiframeImageIds(imageIds)

  imageIds.forEach((imageId) => {
    let instanceMetaData =
      cornerstoneDICOMImageLoader.wadors.metaDataManager.get(imageId)

    // It was using JSON.parse(JSON.stringify(...)) before but it is 8x slower
    instanceMetaData = removeInvalidTags(instanceMetaData)

    if (instanceMetaData) {
      // Add calibrated pixel spacing
      const metadata = DicomMetaDictionary.naturalizeDataset(instanceMetaData)
      const pixelSpacing = getPixelSpacingInformation(metadata)
      let obj = {}
      for (const key in DICOM_TAG_ATTR) {
        if (Array.isArray(metadata[key])) {
          obj[key] = ''
        } else {
          obj[key] = metadata[key]
        }
      }
      getImgInfoProvider.add(imageId, obj)
      if (pixelSpacing) {
        calibratedPixelSpacingMetadataProvider.add(imageId, {
          rowPixelSpacing: parseFloat(pixelSpacing[0]),
          columnPixelSpacing: parseFloat(pixelSpacing[1])
        })
      }
    }
  })
  // we don't want to add non-pet
  // Note: for 99% of scanners SUV calculation is consistent bw slices
  if (modality === 'PT') {
    const InstanceMetadataArray = []
    imageIds.forEach((imageId) => {
      const instanceMetadata = getPTImageIdInstanceMetadata(imageId)

      // TODO: Temporary fix because static-wado is producing a string, not an array of values
      // (or maybe dcmjs isn't parsing it correctly?)
      // It's showing up like 'DECY\\ATTN\\SCAT\\DTIM\\RAN\\RADL\\DCAL\\SLSENS\\NORM'
      // but calculate-suv expects ['DECY', 'ATTN', ...]
      if (typeof instanceMetadata.CorrectedImage === 'string') {
        instanceMetadata.CorrectedImage =
          instanceMetadata.CorrectedImage.split('\\')
      }

      if (instanceMetadata) {
        InstanceMetadataArray.push(instanceMetadata)
      }
    })
    if (InstanceMetadataArray.length) {
      try {
        const suvScalingFactors = calculateSUVScalingFactors(
          InstanceMetadataArray
        )
        InstanceMetadataArray.forEach((instanceMetadata, index) => {
          ptScalingMetaDataProvider.addInstance(
            imageIds[index],
            suvScalingFactors[index]
          )
        })
      } catch (error) {
        console.log(error)
      }
    }
  }

  return imageIds
}
